package com.fancy.learncenter.ui.view;

import android.content.Context;
import android.support.annotation.Nullable;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

import static android.widget.AbsListView.OnScrollListener.SCROLL_STATE_FLING;
import static android.widget.AbsListView.OnScrollListener.SCROLL_STATE_TOUCH_SCROLL;

/**
 * Created by hyy on 2018/4/18.
 */

public class HorizonSlideRecycleView extends RecyclerView {
    private boolean mSnapEnabled = false;
    private boolean mUserScrolling = false;
    private boolean mScrolling = false;
    private int mScrollState;
    private long lastScrollTime = 0;
    private final static int MINIMUM_SCROLL_EVENT_OFFSET_MS = 20;

    public HorizonSlideRecycleView(Context context) {
        this(context, null);
    }

    public HorizonSlideRecycleView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    public void setSnapEnabled(boolean enabled) {
        mSnapEnabled = enabled;
        if (enabled) {
            addOnScrollListener(new OnScrollListener() {
                @Override
                public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                    super.onScrolled(recyclerView, dx, dy);
                }

                @Override
                public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
                    super.onScrollStateChanged(recyclerView, newState);
                    if (newState == SCROLL_STATE_TOUCH_SCROLL && !mScrolling) { //正在滚动
                        mUserScrolling = true;
                    } else if (newState == SCROLL_STATE_FLING) {
                        mScrolling = true;
                    } else if (newState == SCROLL_STATE_IDLE) {//停止滚动时
                        if (mUserScrolling) {
                            scrollToView(getCenterView());
                        }
                        mUserScrolling = false;
                        mScrolling = false;
                    }
                    mScrollState = newState;
                }
            });
        } else {
            addOnScrollListener(null);
        }
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        if (!mSnapEnabled) {
            return super.dispatchTouchEvent(event);
        }
        long currentTime = System.currentTimeMillis();

        /** if touch events are being spammed, this is due to user scrolling right after a tap,
         * so set userScrolling to true **/
        if (mScrolling && mScrollState == SCROLL_STATE_TOUCH_SCROLL) {
            if ((currentTime - lastScrollTime) < MINIMUM_SCROLL_EVENT_OFFSET_MS) {
                mUserScrolling = true;
            }
        }
        lastScrollTime = currentTime;
        View targetView = getChildClosestToPosition((int) event.getX());
        if (!mUserScrolling) {
            if (event.getAction() == MotionEvent.ACTION_UP) {
                if (targetView != getCenterView()) {
                    scrollToView(targetView);
                    return true;
                }
            }
        }
        return super.dispatchTouchEvent(event);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent e) {
        if (!mSnapEnabled) {
            return super.onInterceptTouchEvent(e);
        }
        View targetView = getChildClosestToPosition((int) e.getX());
        if (targetView != getCenterView()) {
            return true;
        }
        return super.onInterceptTouchEvent(e);
    }

    private View getChildClosestToPosition(int x) {
        if (getChildCount() <= 0) {
            return null;
        } else {
            int itemWidth = getChildAt(0).getMeasuredWidth();
            int closestX = 9999;
            View closestChild = null;
            for (int i = 0; i < getChildCount(); i++) {
                View child = getChildAt(i);
                int childCenterX = ((int) child.getX() + (itemWidth / 2));
                int xDistance = childCenterX - x;
                /** if child center is closer than previous closest, set it as closest  **/
                if (Math.abs(xDistance) < Math.abs(closestX)) {
                    closestX = xDistance;
                    closestChild = child;
                }
            }
            return closestChild;
        }
    }

    private View getCenterView() {
        return getChildClosestToPosition(getMeasuredWidth() / 2);
    }

    private void scrollToView(View child) {
        if (child == null)
            return;
        stopScroll();
        int scrollDistance = getScrollDistance(child);
        if (scrollDistance != 0)
            smoothScrollBy(scrollDistance, 0);
    }

    private int getScrollDistance(View child) {
        int x = (int) child.getX();
        int scrollX = child.getScrollX();
        return x - scrollX;
    }

    @Override
    public boolean fling(int velocityX, int velocityY) {
        return super.fling(velocityX, velocityY);
    }
}
